﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using TvControl;
using TvDatabase;

namespace TVServerComm
{
    /// <summary>
    /// Handles all communication to the MediaPortal TV Server
    /// </summary>
    public class TVServer
    {
        private IList groups;
        private IList channels;
        private IList mappings;
        private IList cards;
        private User me;
        private bool _isTimeShifting = false;
        private Exception lastException = null;
        private VirtualCard virtualCard = null;
        private string connectionString;
        private string provider;

        /// <summary>
        /// Last known exception
        /// </summary>
        public Exception LastException
        {
            get { return lastException; }
        }

        /// <summary>
        /// List of available channels
        /// </summary>
        public IList Channels
        {
            get { return channels; }
        }

        /// <summary>
        /// List of available channel groups
        /// </summary>
        public IList ChannelGroups
        {
            get { return groups; }
        }

        /// <summary>
        /// Database connection string
        /// </summary>
        public string ConnectionString
        {
            get { return connectionString; }
        }

        /// <summary>
        /// Database provider
        /// </summary>
        public string Provider
        {
            get { return provider; }
        }

        /// <summary>
        /// Connects to a TV Server
        /// </summary>
        /// <param name="hostname"></param>
        /// <returns></returns>
        public bool Connect(string hostname)
        {
            try
            {
                RemoteControl.HostName = hostname;
                RemoteControl.Instance.GetDatabaseConnectionString(out connectionString, out provider);
                Gentle.Framework.ProviderFactory.SetDefaultProviderConnectionString(connectionString);
                me = new User();
                me.IsAdmin = true;
                groups = ChannelGroup.ListAll();
                channels = Channel.ListAll();
                mappings = GroupMap.ListAll();
                cards = Card.ListAll();
            }
            catch (Exception ex)
            {
                lastException = ex;
                RemoteControl.Clear();
                return false;
            }
            return true;
        }

        /// <summary>
        /// Disconnects from the tv server
        /// </summary>
        public void Disconnect()
        {
            if (_isTimeShifting)
                StopTimeShifting();

            RemoteControl.Clear();
            _isTimeShifting = false;
        }

        /// <summary>
        /// Retrieves a list of channel groups
        /// </summary>
        /// <returns></returns>
        public List<ChannelGroup> GetGroupNames()
        {
            if (!RemoteControl.IsConnected)
                return null;

            List<ChannelGroup> groups = new List<ChannelGroup>();
            try
            {
                foreach (ChannelGroup group in this.groups)
                    groups.Add(group);
            }
            catch (Exception ex)
            {
                lastException = ex;
                return null;
            }

            return groups;
        }

        /// <summary>
        /// Retrieves a list of channels in the specified group
        /// </summary>
        /// <param name="groupName">Group name</param>
        /// <returns>A list of channels</returns>
        public List<ChannelInfo> GetChannelInfosForGroup(string groupName)
        {
            List<ChannelInfo> channelList = new List<ChannelInfo>();
            try
            {
                foreach (ChannelGroup group in groups)
                {
                    if (group.GroupName == groupName)
                    {
                        TvDatabase.Program epg;
                        foreach (GroupMap map in group.ReferringGroupMap())
                        {
                            ChannelInfo channelInfo = new ChannelInfo();
                            channelInfo.channelID = map.ReferencedChannel().IdChannel.ToString();
                            channelInfo.name = map.ReferencedChannel().DisplayName;

                            epg = map.ReferencedChannel().CurrentProgram;
                            channelInfo.epgNow = new ProgramInfo();
                            if (epg != null)
                            {
                                channelInfo.epgNow.timeInfo = epg.StartTime.ToShortTimeString() + "-" + epg.EndTime.ToShortTimeString();
                                channelInfo.epgNow.title = epg.Title;
                                channelInfo.epgNow.description = epg.Description;
                            }

                            epg = map.ReferencedChannel().NextProgram;
                            channelInfo.epgNext = new ProgramInfo();
                            if (epg != null)
                            {
                                channelInfo.epgNext.timeInfo = epg.StartTime.ToShortTimeString() + "-" + epg.EndTime.ToShortTimeString();
                                channelInfo.epgNext.title = epg.Title;
                                channelInfo.epgNext.description = epg.Description;
                            }
                            channelList.Add(channelInfo);
                        }
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                lastException = ex;
                return null;
            }
            return channelList;
        }

        /// <summary>
        /// Starts timeshifting on the specified channel
        /// </summary>
        /// <param name="idChannel">Channel Id</param>
        /// <param name="rtspURL">Returning URL for stream</param>
        /// <returns></returns>
        public TvResult StartTimeShifting(int idChannel, ref string rtspURL)
        {
            if (_isTimeShifting)
                StopTimeShifting();
            TvResult result;

            if (me == null)
                me = new User();

            try
            {
                result = RemoteControl.Instance.StartTimeShifting(ref me, idChannel, out virtualCard);
            }
            catch (Exception ex)
            {
                lastException = ex;
                return TvResult.UnknownError;
            }

            if (result == TvResult.Succeeded)
            {
                _isTimeShifting = true;
                rtspURL = virtualCard.RTSPUrl;
            }

            return result;
        }

        /// <summary>
        /// Stops the timeshifting
        /// </summary>
        /// <returns></returns>
        public bool StopTimeShifting()
        {
            if (!_isTimeShifting || virtualCard == null)
                return true;
            bool result = true;
            try
            {
                virtualCard.StopTimeShifting();
                virtualCard = null;
            }
            catch (Exception ex)
            {
                lastException = ex;
                return false;
            }
            _isTimeShifting = false;
            return result;
        }
    }
}
